#include <stdio.h>
#include "cJSON.h"
#include "random.h"
#include "resource_model.h"
#include "test-bench.h"

/** Select 10E9 modes and check each mode gets selected the expected number of times within 10E4. */
#define MODES_SAMPLE_SIZE 100000000

mode_definition_list *test_modes[HASHSIZE];

resource_model *test_modes_model;

int mode_samples[4] = {0,0,0,0};

void *modes_test1(void *args) {
  mode_samples[0]++;
}

void *modes_test2(void *args) {
  mode_samples[1]++;
}

void *modes_test3(void *args) {
  mode_samples[2]++;
}

void *modes_test4(void *args) {
  mode_samples[3]++;
}

mode * setup_test1(cJSON *json) {
  mode *m = malloc(sizeof(mode));
  cJSON *json_probability = cJSON_GetObjectItem(json,"p");
  m->key = "test1";
  m->function = modes_test1;
  m->probability = json_probability->valuedouble;
  return m;
}

mode * setup_test2(cJSON *json) {
  mode *m = malloc(sizeof(mode));
  cJSON *json_probability = cJSON_GetObjectItem(json,"p");
  m->key = "test2";
  m->function = modes_test2;
  m->probability = json_probability->valuedouble;
  return m;
}

mode * setup_test3(cJSON *json) {
  mode *m = malloc(sizeof(mode));
  cJSON *json_probability = cJSON_GetObjectItem(json,"p");
  m->key = "test3";
  m->function = modes_test3;
  m->probability = json_probability->valuedouble;
  return m;
}

mode * setup_test4(cJSON *json) {
  mode *m = malloc(sizeof(mode));
  cJSON *json_probability = cJSON_GetObjectItem(json,"p");
  m->key = "test4";
  m->function = modes_test4;
  m->probability = json_probability->valuedouble;
  return m;
}

resource_model *setup_modes_test_model(cJSON *json) {
  install_mode(test_modes, "test1", setup_test1);
  install_mode(test_modes, "test2", setup_test2);
  install_mode(test_modes, "test3", setup_test3);
  install_mode(test_modes, "test4", setup_test4);
  resource_model *model = malloc(sizeof(resource_model));
  model->birth = NULL;
  model->state = NULL;
  model->modes = initialize_modes(test_modes, json);
  model->cnt_modes = count_modes(json);
  return model;
}

void setup_modes_test() {
  setup_random_environment();
  test_modes_model = setup_modes_test_model(cJSON_Parse("{\"modes\":[{\"name\":\"test1\",\"p\":0.2},{\"name\":\"test2\",\"p\":0.25},{\"name\":\"test3\",\"p\":0.15},{\"name\":\"test4\",\"p\":0.4}]}"));
}

int modes_test() {
  int i = 0;
  mode *tmp;
  for(i; i < MODES_SAMPLE_SIZE; i++) {
    tmp = select_mode(test_modes_model);
    tmp->function(NULL);
  }

  return !(test_matches_val(mode_samples[0], 20000000, 10000)
           && test_matches_val(mode_samples[1], 25000000, 10000)
           && test_matches_val(mode_samples[2], 15000000, 10000)
           && test_matches_val(mode_samples[3], 40000000, 10000));
}

int main() {
  wg_test(setup_modes_test, "Mode Selection", modes_test);
  return 0;
}
